#include "world.h"

CWorld::CWorld()
{
	terrain = new CTerrain(32, 0.5);
}

CWorld::~CWorld()
{
	delete gui;
	delete terrain;
	terrain = NULL;
	gui = NULL;
	delete audioSystem;
	delete hud;
}

CWorld::CWorld(CCamera *c)
{
	camera = c;
	terrain = new CTerrain(32, 1.0f);

	player = new CPlayer;

	audioSystem = new CDirectXAudio;

	gui = new CGUI;
	hud = new Hud;
	gameDone = false;

	player->AttachTo(terrain);
	player->SetCamera(camera);
	player->SetTerrain(terrain);

	audioSystem->PlaySoundDX(audioSystem->iAmbient);
	player->SetAudioSystem(audioSystem);

	LoadWorld();
	timeStart = 300.0;			// 300 seconds = 5 minutes
	timeElapsed = 0.0;
	gui->SetCurrentTime(timeStart);
	gui->SetEnemiesLeft(numOgros + numSods + numDroids);
}

void CWorld::Animate(float deltaTime)
{
	// set camera height based on player position on terrain
	float ground = player->position.y  = camera->position.y = terrain->GetHeight(camera->position.x, camera->position.z) + player->size;
	
	camera->position.x = std::max( std::min( camera->position.x, terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth() ), terrain->GetScanDepth() );
	if (camera->position.z <= terrain->GetScanDepth())
		camera->position.z = terrain->GetScanDepth();
	if (camera->position.z >= terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth())
		camera->position.z = terrain->GetWidth()*terrain->GetMul() - terrain->GetScanDepth();

	terrain->Animate(deltaTime);   // animate terrain

	const type_info &ogro = typeid(COgroEnemy);  // get ogro typeid
	const type_info &sod = typeid(CSodEnemy);    // get sod typeid
	const type_info &droid = typeid(CDroidEnemy);    // get trooper typeid

	numOgros = CountObjectTypes(ogro);           // count ogros
	numSods = CountObjectTypes(sod);             // count sods
	numDroids = CountObjectTypes(droid);             // count troopers


	gui->SetEnemiesLeft(numOgros + numSods + numDroids);
	gui->SetCurrentTime(timeStart - timeElapsed);

	if (!gameDone)
		timeElapsed += deltaTime;
	else
		timeElapsed = timeStart;


}

void CWorld::FadeScreen()
{
	glPushMatrix();
	glLoadIdentity();
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_TEXTURE_2D);
	glColor4f(0.0f, 0.0f, 0.0f, 0.7f);
	glBegin(GL_QUADS);
	glVertex3f(-5, -5, -3.0);
	glVertex3f(5, -5, -3.0);
	glVertex3f(5, 5, -3.0);
	glVertex3f(-5, 5, -3.0);
	glEnd();
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
	glPopMatrix();
}

void CWorld::SetScreen(int width, int height)
{
	screenWidth = width;
	screenHeight = height;
}

void CWorld::Draw(CCamera *camera)
{
	terrain->Draw(camera);

	gui->Draw();
	
	hud->Render(this->GetEnemies(), player, this->camera, this->worldCloseDistance, this->worldFarDistance);

	if (player->getHitPoints() < 0)
	{
		gameDone = true;
	}
	player->hitCountDown();
	
	if (gameDone)
	{
		FadeScreen();
		if (numOgros + numSods + numDroids <=0)
			gui->DrawWinner();
		else
			gui->DrawLoser();
	}

}

void CWorld::OnPrepare()
{
	glClearColor(terrain->fogColor[0], terrain->fogColor[1], terrain->fogColor[2], terrain->fogColor[3]);
	terrain->Prepare();

	if ((numOgros + numSods + numDroids <= 0) || (timeElapsed >= timeStart))
		gameDone = true;
	
}


// LoadWorld()
// desc: initializes the world
void CWorld::LoadWorld()
{
	int enemyIdx = 0;
	int rndInt = 0;

	numOgros = 0;
	numSods = 0;
	numDroids = 0;

	srand((unsigned int)time(NULL)); 
	
	rndInt = (rand() % (MAX_ENEMIES-4)) + 4;	// random # from 4 to MAX
	numOgros = numSods = numDroids = rndInt;

	// generate ogros
	for (enemyIdx = 0; enemyIdx < numOgros; enemyIdx++)
	{
		ogroEnemy = new COgroEnemy;
		ogroEnemy->AttachTo(terrain);
		ogroEnemy->SetPlayer(player);
		ogroEnemy->SetAudioSystem(audioSystem);
		ogroEnemy->LoadAudio(audioSystem->iWilhelm);
		ogroEnemy->position.x = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
		ogroEnemy->position.y = 0.0f;
		ogroEnemy->position.z = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
	}

	// generate sods
	for (enemyIdx = 0; enemyIdx < numSods; enemyIdx++)
	{
		sodEnemy = new CSodEnemy;
		sodEnemy->AttachTo(terrain);
		sodEnemy->SetPlayer(player);
		sodEnemy->SetAudioSystem(audioSystem);
		sodEnemy->LoadAudio(audioSystem->iWilhelm);
		sodEnemy->position.x = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
		sodEnemy->position.y = 0.0f;
		sodEnemy->position.z = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
	}
	// generate droids
	for (enemyIdx = 0; enemyIdx < numDroids; enemyIdx++)
	{
		droidEnemy = new CDroidEnemy;
		droidEnemy->AttachTo(terrain);
		droidEnemy->SetPlayer(player);
		droidEnemy->SetAudioSystem(audioSystem);
		droidEnemy->position.x = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
		droidEnemy->position.y = 0.0f;
		droidEnemy->position.z = (float)(rand() % (int)(terrain->GetWidth() * terrain->GetMul()));
	}
}
// CountObjectTypes
// desc: counts the number of objects passed as classID in the hierarchy
int CWorld::CountObjectTypes(const type_info &classID)
{
	int count = 0;
	CObject *c1;
	CObject *c2;

	c1 = (CObject*)terrain->childNode;

	while (c1 != NULL)
	{
		c2 = c1;
		do
		{
			if (typeid(*c2) == classID)
				count++;
			c2 = (CObject*)c2->nextNode;
		} while (!c2->IsFirstChild());

		c1 = (CObject*)c1->childNode;
	}

	return count;
}


std::vector<CEnemy*> CWorld::GetEnemies()
{
	vector<CEnemy*> enemies;
	CObject *c1;
	CObject *c2;

	c1 = (CObject*)terrain->childNode;

	while (c1 != NULL)
	{
		c2 = c1;
		do
		{
			if (typeid(*c2) == typeid(COgroEnemy) || typeid(*c2) == typeid(CSodEnemy) || typeid(*c2) == typeid(CDroidEnemy) )
			{
				enemies.push_back((CEnemy*)c2);
			}
			c2 = (CObject*)c2->nextNode;
		} while (!c2->IsFirstChild());
//		count--;

		c1 = (CObject*)c1->childNode;
	}
	return enemies;
}

void CWorld::setWorldDistance(float c, float f)
{
	worldCloseDistance  = c;
	worldFarDistance = f;
}

float CWorld::getCloseDistance()
{
	return worldCloseDistance;
}

float CWorld::getFarDistance()
{
	return worldFarDistance;
}

